/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.metadata.rtcustomization.servermanager;

import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.I18nResource;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4Ref;
import com.inspur.edp.lcm.metadata.api.entity.MetadataDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataRTFilter;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.entity.MetadataType;
import com.inspur.edp.lcm.metadata.api.entity.ProcessMode;
import com.inspur.edp.lcm.metadata.api.entity.uri.MetadataURI;
import com.inspur.edp.lcm.metadata.cache.*;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.MetadataDtoConverter;
import com.inspur.edp.lcm.metadata.common.ServiceUtils;
import com.inspur.edp.lcm.metadata.common.configuration.I18nManagerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataTypeHelper;
import com.inspur.edp.lcm.metadata.common.context.RuntimeContext;
import com.inspur.edp.lcm.metadata.spi.MetadataI18nService;
import com.inspur.edp.metadata.rtcustomization.api.AbstractCustomizedContent;
import com.inspur.edp.metadata.rtcustomization.api.entity.*;
import com.inspur.edp.metadata.rtcustomization.api.exception.ErrorCodes;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmMetadataCustomizationException;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmMetadataException;
import com.inspur.edp.metadata.rtcustomization.common.CheckerHelper;
import com.inspur.edp.metadata.rtcustomization.common.CustomizedServiceHelper;
import com.inspur.edp.metadata.rtcustomization.common.EnvironmentContext;
import com.inspur.edp.metadata.rtcustomization.common.MetadataCustomizationUtils;
import com.inspur.edp.metadata.rtcustomization.common.ReferenceHelper;
import com.inspur.edp.metadata.rtcustomization.inner.api.I18nResourceRTService;
import com.inspur.edp.metadata.rtcustomization.inner.api.utils.I18nResourceRTUtils;
import com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.CustomizationDataProducer;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.CustomizationExtRelationRepo;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.CustomizationMetadataRefsRepository;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.CustomizationMetadataRepository;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.GspMdpkgRepository;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.MetadataChangesetRepository;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.MetadataChangesetRepositoryHis;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.MetadataContentHisRepository;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.MetadataContentRepository;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.MetadataRtContentRepository;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.ChangeSetRepoService;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.CustomizationRepoService;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.ExtRelationRepoService;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.GeneratedRepoService;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.MdRtRepoService;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.MetadataRefsRepoService;
import com.inspur.edp.metadata.rtcustomization.servermanager.utils.MetadataStorageUtils;
import com.inspur.edp.metadata.rtcustomization.spi.CustomizationExtChecker;
import com.inspur.edp.metadata.rtcustomization.spi.CustomizationExtHandler;
import com.inspur.edp.metadata.rtcustomization.spi.IMetadataRtReferenceManager;
import com.inspur.edp.metadata.rtcustomization.spi.args.ChangeMergeArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.ExtContentArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.MdConflictCheckArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.MetadataMergeArgs;
import com.inspur.edp.metadata.rtcustomization.spi.event.MetadataRtEventArgs;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.transaction.JpaTransaction;
import io.iec.edp.caf.commons.transaction.TransactionPropagation;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.lock.service.api.api.DistributedLock;
import io.iec.edp.caf.lock.service.api.api.DistributedLockFactory;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.data.util.Pair;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
public class CustomizationServerServiceImpl extends AbstractMetadataService implements CustomizationServerService {
    private final CustomizationRepoService repoService;
    private final ChangeSetRepoService changesetRepoService;
    private final ExtRelationRepoService extRelationRepoService;
    private final MetadataRefsRepoService metadataRefsRepoService;
    private final MetadataContentRepository mdContentRepo;

    MetadataCustomizationUtils utils;

    static {
        // 在启动过程中，注册bean的时候调用缓存清理方法，确保获取的元数据都是最新的。
        MetadataDistCacheManager.getMetadataCache().clear();
    }

    public CustomizationServerServiceImpl(CustomizationMetadataRepository metadataRepository,
        CustomizationMetadataRefsRepository metadataRefsRepository,
        CustomizationExtRelationRepo extRelationRepo, MetadataContentRepository mdContentRepo,
        MetadataContentHisRepository mdContentHisRepo,
        MetadataRtContentRepository mdRtContentRepo, MetadataChangesetRepository changesetRepo,
        MetadataChangesetRepositoryHis changesetHisRepo,
        CustomizationDataProducer cdp, GspMdpkgRepository gspMdpkgRepository) {
        changesetRepoService = new ChangeSetRepoService(changesetRepo, changesetHisRepo);
        generatedRepoService = new GeneratedRepoService(metadataRepository, metadataRefsRepository, cdp);
        metadataRefsRepoService = new MetadataRefsRepoService(metadataRefsRepository);
        repoService = new CustomizationRepoService(mdContentRepo, mdContentHisRepo, cdp, metadataRefsRepository, metadataRefsRepoService);
        extRelationRepoService = new ExtRelationRepoService(extRelationRepo);
        mdRtRepoService = new MdRtRepoService(mdRtContentRepo, gspMdpkgRepository,cdp);
        utils = new MetadataCustomizationUtils();
        this.mdContentRepo = mdContentRepo;
    }

    @Override
    public List<Metadata4Ref> getMetadataInfoListWithTypes(String metadataTypes) {
        MetadataFilter metadataFilter = StringUtils.isEmpty(metadataTypes) ? null : new MetadataFilter(new ArrayList<>(Arrays.asList(metadataTypes.split(","))));
        return getMetadataListByFilter(metadataFilter);
    }

    @Override
    public List<Metadata4Ref> getMetadata4Refs(List<String> metadataTypes,List<SourceTypeEnum> sourceTypeEnumList){
        if(CollectionUtils.isEmpty(sourceTypeEnumList)){
            return null;
        }
        List<Metadata4Ref> metadata4RefList = new ArrayList<>();
        if(sourceTypeEnumList.contains(SourceTypeEnum.CUSTOMIZING)){
            //获取运行定制的元数据列表
            List<Metadata4Ref> customizingList = repoService.getAllCustomizedMetadata(metadataTypes, true);
            if (!CollectionUtils.isEmpty(customizingList)) {
                metadata4RefList.addAll(customizingList);
            }
        }
        if(sourceTypeEnumList.contains(SourceTypeEnum.GENERATED)){
            //获取运行时生成的元数据列表
            List<Metadata4Ref> generatedList = generatedRepoService.getAllRTGeneratedMetadata(metadataTypes,true);
            if (!CollectionUtils.isEmpty(generatedList)) {
                metadata4RefList.addAll(generatedList);
            }
        }
        if(sourceTypeEnumList.contains(SourceTypeEnum.MDPKG)){
            // 获取MDPKG元数据
            List<Metadata4Ref> mdpkgMetadataList = mdRtRepoService.getMetadata4RefList(metadataTypes, SourceTypeEnum.MDPKG);
            if (!CollectionUtils.isEmpty(mdpkgMetadataList)) {
                metadata4RefList.addAll(mdpkgMetadataList);
            }
        }
        if(sourceTypeEnumList.contains(SourceTypeEnum.CUSTOMIZED)){
            // 获取CUSTOMIZED元数据
            List<Metadata4Ref> customizedList = mdRtRepoService.getAllCustomizedMetadata(metadataTypes, true);
            if (!CollectionUtils.isEmpty(customizedList)) {
                metadata4RefList.addAll(customizedList);
            }
        }
        if(sourceTypeEnumList.contains(SourceTypeEnum.NOCODE)){
            // 获取NOCODE元数据
            List<Metadata4Ref> noCodeList = mdRtRepoService.getAllNoCodeMetadata(metadataTypes);
            if (!CollectionUtils.isEmpty(noCodeList)) {
                metadata4RefList.addAll(noCodeList);
            }
        }
        return metadata4RefList;
    }


    /**
     * 分页查询获取元数据列表
     *
     * @param
     * @return
     */
    public Metadata4RefPageQueryResult getMetadata4RefsByQueryParam(Metadata4RefPageQueryParam metadata4RefQueryParam) {
        List<SourceTypeEnum> sourceTypeEnumList = metadata4RefQueryParam.getSourceTypeEnumList();
        if (CollectionUtils.isEmpty(sourceTypeEnumList)) {
            return new Metadata4RefPageQueryResult();
        }

        String keyword = metadata4RefQueryParam.getKeyword();
        List<String> metadataTypeList = metadata4RefQueryParam.getMetadataTypeList();
        int localMdCount = metadata4RefQueryParam.getLocalMdCount();
        int localMdPageCount = metadata4RefQueryParam.getLocalMdPageCount();
        int pageSize = metadata4RefQueryParam.getPageSize();
        int pageIndex = metadata4RefQueryParam.getPageIndex();
        String bizobjectID = metadata4RefQueryParam.getBizobjectID();

        // 查询元数据在各表的总数量
        int generatedMdCount = generatedRepoService.getRTGeneratedMetadataCountByCondition(metadataTypeList, keyword, bizobjectID);
        int mdpkgCount = mdRtRepoService.getGspMdRtContentsCountByCondition(metadataTypeList, keyword, bizobjectID, SourceTypeEnum.MDPKG);
        int customizedMdCount = sourceTypeEnumList.contains(SourceTypeEnum.CUSTOMIZED) ? mdRtRepoService.getGspMdRtContentsCountByCondition(metadataTypeList, keyword, bizobjectID, SourceTypeEnum.CUSTOMIZED) : 0;

        int totalCount = generatedMdCount + mdpkgCount + customizedMdCount;
        // 如果本地元数据已经满足分页查询，则只查询数据库的总数量
        if (localMdPageCount == pageSize) {
            return new Metadata4RefPageQueryResult(new ArrayList(), totalCount);
        }
        // 根据分页信息计算每个数据源要查询的实际数据， 可变参数的顺序就是与实际查询元数据的顺序相对应
        List<Pair<Integer, Integer>> resultPairList = calculatePageIndices(pageIndex, pageSize, localMdCount, generatedMdCount, mdpkgCount, customizedMdCount);
        Pair<Integer, Integer> generatedMdPair = resultPairList.get(1);
        Pair<Integer, Integer> mdpkgPair = resultPairList.get(2);
        Pair<Integer, Integer> customizedMdPair = resultPairList.get(3);

        List<Metadata4Ref> metadata4RefList = new ArrayList<>();
        if (sourceTypeEnumList.contains(SourceTypeEnum.GENERATED) && generatedMdPair.getSecond() > 0) {
            //获取运行时生成的元数据列表 GspMdCustomContent
            List<Metadata4Ref> generatedList = generatedRepoService.getRTGeneratedMetadataListByCondition(metadataTypeList, keyword, bizobjectID, generatedMdPair.getFirst(), generatedMdPair.getSecond(), true);
            if (!CollectionUtils.isEmpty(generatedList)) {
                metadata4RefList.addAll(generatedList);
            }
        }
        if (sourceTypeEnumList.contains(SourceTypeEnum.MDPKG) && mdpkgPair.getSecond() > 0) {
            // 获取MDPKG元数据  GspMdRtContent
            List<Metadata4Ref> mdpkgMetadataList = mdRtRepoService.getMetadata4RefListByCondition(metadataTypeList, keyword, bizobjectID, SourceTypeEnum.MDPKG, mdpkgPair.getFirst(), mdpkgPair.getSecond());
            if (!CollectionUtils.isEmpty(mdpkgMetadataList)) {
                metadata4RefList.addAll(mdpkgMetadataList);
            }
        }
        if (sourceTypeEnumList.contains(SourceTypeEnum.CUSTOMIZED) && customizedMdPair.getSecond() > 0) {
            // 获取CUSTOMIZED元数据 GspMdRtContent
            List<Metadata4Ref> customizedList = mdRtRepoService.getCustomizedMetadataListByCondition(metadataTypeList, keyword, bizobjectID, SourceTypeEnum.CUSTOMIZED, true, customizedMdPair.getFirst(), customizedMdPair.getSecond());
            if (!CollectionUtils.isEmpty(customizedList)) {
                metadata4RefList.addAll(customizedList);
            }
        }

        return new Metadata4RefPageQueryResult(metadata4RefList, totalCount);
    }

    /**
     * 计算页面索引列表。
     * 该方法根据提供的文档数量、页面大小和页码计算出对应的页面索引范围，并以Pair<Integer, Integer>的形式返回每个页面的起始和结束索引。
     *
     * @param pageSize   每页的文档数量
     * @param pageIndex  请求的页码
     * @param sourceList 各数据源中查询到的元数据的数量，依次是本地元数据、GspMdCustomContent、GspMdRtContent（MDPKG）、GspMdRtContent（CUSTOMIZED）
     * @return
     */
    public List<Pair<Integer, Integer>> calculatePageIndices(int pageIndex, int pageSize, int... sourceList) {

        List<Pair<Integer, Integer>> result = new ArrayList<>();
        // 当前页查询数据库元数据的起始索引
        int startIndex = (pageIndex - 1) * pageSize;
        // 当前页剩余的可用空间大小
        int remainingPageSize = pageSize;
        // 从每个集合中分页取数
        for (Integer sourceSize : sourceList) {
            Pair<Integer, Integer> pair = Pair.of(0, 0);

            if (startIndex >= sourceSize) {
                // 当前集合的起始索引已超过集合大小，不再进行取数
                startIndex -= sourceSize;
                result.add(pair);
                continue;
            }

            int endIndex = Math.min(startIndex + remainingPageSize - 1, sourceSize - 1);
            int takenSize = endIndex - startIndex + 1;
            result.add(Pair.of(startIndex, takenSize));
            remainingPageSize -= takenSize; // 更新剩余可用空间大小
            if (remainingPageSize <= 0) {
                break;
            }
            startIndex = 0; // 更新起始索引
        }

        if (result.size() < sourceList.length) {
            for (int i = 0; i <= sourceList.length - result.size(); i++) {
                result.add(Pair.of(0, 0));
            }
        }
        return result;
    }

    @Override
    public List<MetadataDto> getAllBySourceTypeAndBizObjectID(Integer sourceType, String bizObjectID){
        return repoService.findAllBySourcetypeAndBizObjID(sourceType, bizObjectID);
    }

    @Override
    public void updateExtRelation(DimensionExtendRelation extendRelation) {
        if (Objects.isNull(extendRelation)){
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0009);
        }
        if(StringUtils.isEmpty(extendRelation.getExtMdId())){
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0010);
        }
        GspMdExtRelation existExtRelation = extRelationRepoService.getExtRelationByExtMdIdAndCertId(extendRelation.getExtMdId(), extendRelation.getExtMdCertId());
        if (Objects.isNull(existExtRelation)){
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0011, extendRelation.getExtMdId(), extendRelation.getExtMdNameSpace(),extendRelation.getExtMdCode(),extendRelation.getExtMdType());
        }
        //构造新的扩展关系，替换新维度值
        updateDimInfo(existExtRelation, extendRelation);
        extRelationRepoService.save(existExtRelation);
    }

    private void updateDimInfo(GspMdExtRelation existRelation, DimensionExtendRelation newDimInfo) {
        if (!StringUtils.isEmpty(newDimInfo.getFirstDimCode())) {
            existRelation.setFirstDimCode(newDimInfo.getFirstDimCode());
        }
        if (!StringUtils.isEmpty(newDimInfo.getFirstDimValue())) {
            existRelation.setFirstDimValue(newDimInfo.getFirstDimValue());
        }
        if (!StringUtils.isEmpty(newDimInfo.getFirstDimName())) {
            existRelation.setFirstDimName(newDimInfo.getFirstDimName());
        }
        if (!StringUtils.isEmpty(newDimInfo.getSecDimCode())) {
            existRelation.setSecDimCode(newDimInfo.getSecDimCode());
        }
        if (!StringUtils.isEmpty(newDimInfo.getSecDimValue())) {
            existRelation.setSecDimValue(newDimInfo.getSecDimValue());
        }
        if (!StringUtils.isEmpty(newDimInfo.getSecDimName())) {
            existRelation.setSecDimName(newDimInfo.getSecDimName());
        }
    }

    @Override
    public MetadataURI getRefMetadataURI(String metadataId) {
        List<GspMdRefs> mdRefsByRefMdId = metadataRefsRepoService.getMdRefsByRefMdId(metadataId);
        if (CollectionUtils.isEmpty(mdRefsByRefMdId)) {
            return null;
        }
        return new MetadataURI(metadataId, mdRefsByRefMdId.get(0).getRefMdCode(), mdRefsByRefMdId.get(0).getRefMdType(), mdRefsByRefMdId.get(0).getRefMdNameSpace());
    }

    @Override
    public List<Metadata4Ref> getCustomizedList(MetadataFilter metadataFilter) {
        if (metadataFilter != null && metadataFilter.getSourceType() != null && metadataFilter.getSourceType() != SourceTypeEnum.CUSTOMIZING) {
            return null;
        }
        return repoService.getAllCustomizedMetadata();
    }

    @Override
    public MetadataDto getMetadataBySemanticId(String nameSpace, String code, String typeCode) {
        List<Metadata4Ref> metadataListByFilter = getMetadataListByFilter(new MetadataFilter(code, typeCode, nameSpace, SourceTypeEnum.MDPKG));
        if (CollectionUtils.isEmpty(metadataListByFilter)) {
            return null;
        }
        GspMetadata metadata = mdRtRepoService.getMetadataByIdSourceType(metadataListByFilter.get(0).getMetadata().getHeader().getId(), SourceTypeEnum.MDPKG.getCode());
        return MetadataDtoConverter.asDto(metadata);
    }

    /**
     * 根据维度值获取已经扩展的元数据（根据基础元数据、两个纬度值获取扩展元数据） 用于新增扩展元数据场景 新增扩展，直接根据元数据id获取基础元数据内容，不需要查询
     *
     * @param basicMetadataId     基础元数据id
     * @param basicMetadataCertId 基础元数据证书id
     * @param firstDimension      第一维度值
     * @param secondDimension     第二维度值
     * @return 元数据传输实体
     */
    @Override
    public MetadataDto getMetadataWithDimensions(String basicMetadataId, String basicMetadataCertId,
        String firstDimension, String secondDimension) {
        if (StringUtils.isEmpty(basicMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "basicMetadataId");
        }
        //根据基础元数据id，维度的值，查找更基础的元数据，获取内容；
        var relations = extRelationRepoService.getRelationByDims(basicMetadataId, basicMetadataCertId, firstDimension, secondDimension);
        if (relations == null) {
            return null;
        } else {
            return getMetadataDtoById(relations.getExtMdId(), relations.getExtMdCertId());
        }
    }

    @Override
    public MetadataDto getMetadataWithRootMdIdAndDimensions(String rootMetadataId, String basicMetadataCertId,
        String firstDimension, String secondDimension) {
        if (StringUtils.isEmpty(rootMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "rootMetadataId");
        }
        List<GspMdExtRelation> relations = new ArrayList<>();
        GspMdExtRelation relation;
        getExtrelationsRecusively(rootMetadataId, basicMetadataCertId, relations);
        if (CollectionUtils.isEmpty(relations)) {
            return null;
        }
        if (StringUtils.isEmpty(firstDimension) && StringUtils.isEmpty(secondDimension)) {
            relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getFirstDimValue()) && StringUtils.isEmpty(item.getSecDimValue())).findAny().orElse(null);
        } else if (StringUtils.isEmpty(firstDimension)) {
            relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getFirstDimValue()) && secondDimension.equals(item.getSecDimValue())).findAny().orElse(null);
        } else if (StringUtils.isEmpty(secondDimension)) {
            relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getSecDimValue()) && firstDimension.equals(item.getFirstDimValue())).findAny().orElse(null);
        } else {
            relation = relations.stream().filter(item -> firstDimension.equals(item.getFirstDimValue()) && secondDimension.equals(item.getSecDimValue())).findAny().orElse(null);
        }
        if (relation == null) {
            return null;
        }
        return getMetadataDto(relation.getExtMdId());
    }

    @Override
    public DimensionExtendRelation getDimExtRelationByExtMetadata(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        var relation = extRelationRepoService.getExtRelationByExtMdIdAndCertId(metadataId, certId);
        if (relation == null) {
            return null;
        }
        return buildDimExtRelationByGspMdExtRelation(relation);
    }

    private DimensionExtendRelation buildDimExtRelationByGspMdExtRelation(GspMdExtRelation relation) {
        DimensionExtendRelation dimExtRelation = new DimensionExtendRelation();
        dimExtRelation.setBasicMdCertId(relation.getBasicMdCertId());
        dimExtRelation.setBasicMdCode(relation.getBasicMdCode());
        dimExtRelation.setBasicMdId(relation.getBasicMdId());
        dimExtRelation.setBasicMdNameSpace(relation.getBasicMdNameSpace());
        dimExtRelation.setBasicMdType(relation.getBasicMdType());
        dimExtRelation.setBasicMdVersion(relation.getBasicMdVersion());
        dimExtRelation.setExtMdCertId(relation.getExtMdCertId());
        dimExtRelation.setExtMdCode(relation.getExtMdCode());
        dimExtRelation.setExtMdId(relation.getExtMdId());
        dimExtRelation.setExtMdNameSpace(relation.getExtMdNameSpace());
        dimExtRelation.setExtMdType(relation.getExtMdType());
        dimExtRelation.setFirstDimValue(relation.getFirstDimValue());
        dimExtRelation.setSecDimValue(relation.getSecDimValue());
        dimExtRelation.setFirstDimName(relation.getFirstDimName());
        dimExtRelation.setFirstDimCode(relation.getFirstDimCode());
        dimExtRelation.setSecDimName(relation.getSecDimName());
        dimExtRelation.setSecDimCode(relation.getSecDimCode());
        return dimExtRelation;
    }

    /**
     * 保存扩展维度上的元数据（增量）
     */
    @Override
    public boolean saveExtMetadataWithDimensions(DimensionExtendEntityDto dimExtEntityDto) {
        if (Objects.isNull(dimExtEntityDto) || Objects.isNull(dimExtEntityDto.getMetadataDto())) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "dimExtEntityDto");

        }
        DimensionExtendEntity dimExtEntity = utils.buildDimensionExtendEntity(dimExtEntityDto);

        //保存扩展内容，包括扩展关系
        //保存内容前，需要先调用检查逻辑（是否能够创建，是否存在合并冲突（能否往下合并，应该有合并检查））
        //存在合并冲突，提示具体的冲突信息
        //无合并冲突，将内容保存到数据库，开启影响处理：元数据保存到数据库中，然后，元数据当前版本与前一版本
        //对比增量，然后增量往下合并：查找扩展的元数据，获取具体的元数据当前版本，与上级增量合并，合并后的新版本内容保存到数据库，
        //版本增加，然后继续往下合并：元数据当前版本与前一版本对比增量，形成增量，然后增量往下合并。

        //考虑减少数据库操作，合并能否从内存中合并完成，然后内容批量插入到数据库中。逻辑流程变为：
        //元数据当前版本与前一版本对比增量，增量往下合并，获取扩展元数据具体版本，与上级增量合并，合并后形成新版本，内存中记录新版本;
        //最终，将记录的各新版本内容尝试统一更新到数据库（这里要确认repo中是否支持批量操作）
        if (dimExtEntity == null) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "dimExtEntity");
        }

        //1.TODO 需要检查当前维度下是否已经存在扩展，如果已经存在，保存的元数据应该是新版本，id、证书相同
        //TODO 扩展链上的元数据修改时，仅能修改一个元数据，需要向上，向下查找元数据关系，需要对元数据加锁。
        //组织基础元数据信息
        GspMetadata metadata = dimExtEntity.getExtendMetadataEntity();
        metadata.setExtended(true);
        buildBasicMetadataInfo(dimExtEntity);
        // 查找资源元数据的引用关系
        MetadataReference resourceMetatadaRef = MetadataCustomizationUtils.isFormTypeMetadata(metadata) ? MetadataCustomizationUtils.findResourceMetatadaRef(metadata) : null;
        // 根据元数据引用扩展重新生成元数据引用关系（不包含资源元数据）
        buildMetadataRef(metadata);
        // 扩展元数据保存对资源元数据的引用关系,目前只记录扩展表单类元数据的资源元数据引用关系
        if (resourceMetatadaRef != null) {
            Optional<MetadataReference> resourceMetadataOp = metadata.getRefs().stream().filter(ref -> ref.getDependentMetadata().getId().equals(resourceMetatadaRef.getDependentMetadata().getId())).findAny();
            if (!resourceMetadataOp.isPresent()) {
                metadata.getRefs().add(resourceMetatadaRef);
            }
        }
        //根据基础元数据id获取基础元数据内容，这个基础元数据可能是某个维度值上扩展的元数据
        GspMetadata basicMetadata = this.getMetadataByIdAndCertId(dimExtEntity.getBasicMetadataId(), dimExtEntity.getBasicMetadataCertId());
        String typeCode = dimExtEntity.getExtendMetadataEntity().getHeader().getType();
        metadataSaveCheck4CustomizingAndNocode(metadata);

        GspMetadata rootMetadata = this.getBasicMdByExtMdId(metadata.getHeader().getId(), metadata.getHeader().getCertId());

        // TODO rootMetadata获取方法有问题，一直为null
        ProcessMode processMode = rootMetadata == null ? ProcessMode.interpretation : getProcessModeByMetadataId(rootMetadata.getHeader().getId());

        fireMetadataSavingEvent(metadata, processMode);

        //2.获取元数据与父级的相对增量
        AbstractCustomizedContent changeToParent = null;
        CustomizationExtHandler manager = CustomizedServiceHelper.getInstance().getManager(typeCode);
        if (manager != null) {
            GspMetadata parentMetadata = getMetadata(dimExtEntity.getBasicMetadataId());
            if (parentMetadata != null) {
                changeToParent = manager.getExtContent(new ExtContentArgs(basicMetadata, metadata, rootMetadata));
            }
        }
        //保存检查,这块内容待确认，现在没有用
        CustomizationExtChecker checker = CheckerHelper.getInstance().getManager(typeCode);
        if (checker != null) {
            try {
                checker.checkMergeConflict(new MdConflictCheckArgs(dimExtEntity, metadata, rootMetadata));
            } catch (Exception e) {
                throw new LcmMetadataCustomizationException(e, ErrorCodes.ECP_METADATA_CUSTOMIZATION_0003, metadata.getHeader().getId(), rootMetadata.getHeader().getId());
            }
        }
        GspMetadata preversionMetadata = repoService.getCurrentMetadata(metadata.getHeader().getId(), metadata.getHeader().getCertId());

        //3.增量对比，是当前元数据与自己的上一个版本对比。尝试向下合并。
        ArrayList<ExtRelationAndMetadata> effectedExtRelationAndMetadata = new ArrayList<>();

        //新增扩展，没有历史版本，无需扩展影响检查
        if (preversionMetadata != null) {
            dimExtEntity.getExtendMetadataEntity().setVersion(String.valueOf(Integer.parseInt(preversionMetadata.getVersion()) + 1));
            dimExtEntity.getExtendMetadataEntity().setPreviousVersion(preversionMetadata.getVersion());
            List<GspMdExtRelation> extRelations = extRelationRepoService.getExtRelationByBasicMdInfo(preversionMetadata.getHeader().getId(), preversionMetadata.getHeader().getCertId());
            if (!CollectionUtils.isEmpty(extRelations)) {
                if (manager != null) {
                    AbstractCustomizedContent change = manager.getExtContent(new ExtContentArgs(preversionMetadata, metadata, rootMetadata));
                    //尝试合并受影响的元数据，同时返回影响内容
                    validateMetadataMergeConflict(manager, preversionMetadata, change, effectedExtRelationAndMetadata, rootMetadata, extRelations);
                }
            }
        } else {
            //没有前一个版本，则版本为1
            dimExtEntity.getExtendMetadataEntity().setVersion("1");
        }

        //4.保存时，保存扩展元数据全量、保存扩展元数据增量，保存扩展关系，版本变化(元数据本身版本变化，扩展关系中新增一行数据：基础元数据版本与扩展元数据版本都变化)
        // 所有的扩展链上元数据内容、扩展关系
        //历史版本需要保留，需要首先将原有版本元数据 放到历史表中，然后保存新版本。保存的内容版本已经是需要保存的版本。
        repoService.saveExtContent(dimExtEntity.getExtendMetadataEntity());
        //TODO 构造内容
        //GspMdChangeset mdChangeset getDimExtRelationByExtMetadata= BuildGspMdChangesetFromGspMetadataAndCustomizedContent(extendMetadataEntity, changeToParent);
        //保存变更历史
        //保存最新变更
        extRelationRepoService.saveMetadataExtRelation(dimExtEntity);
        //保存增量
        if (changeToParent != null) {
            changesetRepoService.saveChangeset(dimExtEntity.getExtendMetadataEntity(), changeToParent);
        }
        saveEffectedExtRelationAndMetadata(effectedExtRelationAndMetadata);

        fireMetadataSavedEvent(metadata, processMode);
        //保存基础元数据、维度值、扩展元数据的关系
        //repoService.saveMetadataExtRelation(dimExtEntity);

        RemoveDistCache(dimExtEntityDto.getMetadataDto().getId());
        return true;
    }

    @Override
    public MetadataDto getParentMdByExtMdId(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }

        GspMdExtRelation relation = extRelationRepoService.getExtRelationByExtMdIdAndCertId(metadataId, certId);
        if (relation == null || StringUtils.isEmpty(relation.getBasicMdId())) {
            return null;
        } else {
            return getMetadataDto(relation.getBasicMdId());
        }
    }

    @Override
    public List<DimensionExtendEntity> getExtMdByBasicMdId(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        List<DimensionExtendEntity> result = new ArrayList<>();
        List<GspMdExtRelation> relations = extRelationRepoService.getExtRelationByBasicMdInfo(metadataId, certId);
        if (CollectionUtils.isEmpty(relations)) {
            return null;
        }
        relations.forEach(relation -> {
            List<GspMdContent> customizedMetadatas = repoService.getCustomizedListByIdAndCertId(relation.getExtMdId(), relation.getExtMdCertId(), relation.getExtMdVersion());
            if (CollectionUtils.isEmpty(customizedMetadatas)) {
                throw new LcmMetadataCustomizationException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0004, metadataId, relation.getExtMdId(), relation.getId());
            }
            result.add(buildDimensionExtendEntity(customizedMetadatas.get(0), relation));
        });
        return result;
    }

    @Override
    public void saveCheck(MetadataDto dto) {
        if (Objects.isNull(dto)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataDto");
        }
        GspMetadata metadata = MetadataDtoConverter.asMetadata(dto);
        metadataSaveCheck(metadata);
    }

    @Override
    public void saveExtMetadata(GspMetadata metadata) {
        //更新元数据版本
        updateMetadaVersion(metadata);
        repoService.saveExtContent(metadata);
        RemoveDistCache(metadata.getHeader().getId());
    }

    public void updateMetadaVersion(GspMetadata metadata) {
        GspMetadata preversionMetadata = repoService.getCurrentMetadata(metadata.getHeader().getId(), metadata.getHeader().getCertId());
        if (preversionMetadata != null) {
            metadata.setVersion(String.valueOf(Integer.parseInt(preversionMetadata.getVersion()) + 1));
            metadata.setPreviousVersion(preversionMetadata.getVersion());
        } else {
            //没有前一个版本，则版本为1
            metadata.setVersion("1");
        }
    }

    public void metadataSaveCheck(GspMetadata metadata) {
        MetadataHeader header = metadata.getHeader();
        String metadataId = header.getId();
        String code = header.getCode();
        String nameSpace = header.getNameSpace();
        String type = metadata.getHeader().getType();
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }

        List<GspMdCustomContent> metadatas = generatedRepoService.getAllByNameSpaceAndCodeAndType(nameSpace, code, type);
        if (metadatas != null && metadatas.size() > 0) {
            metadatas.forEach(item -> {
                if (!item.getId().equals(metadataId)) {
                    throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0018, nameSpace, code, type);
                }
            });
        }

        List<GspMdContent> customMetadatas = repoService.getMetadataInfos(nameSpace, code, type);
        if (customMetadatas != null && customMetadatas.size() > 0) {
            customMetadatas.forEach(item -> {
                if (!item.getMetadataId().equals(metadataId)) {
                    throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0019, nameSpace, code, type);
                }
            });
        }
        if (StringUtils.hasLength(code) && StringUtils.hasLength(type) && StringUtils.hasLength(nameSpace)) {
            List<Metadata4Ref> rtMetadatas = getMetadataListByFilter(new MetadataFilter(code, type, nameSpace, SourceTypeEnum.MDPKG));
            if (rtMetadatas != null && rtMetadatas.size() > 0) {
                rtMetadatas.forEach(item -> {
                    if (!item.getMetadata().getHeader().getId().equals(metadataId)) {
                        throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0014, nameSpace, code, type);
                    }
                });
            }
        }
    }


    public void metadataSaveCheck4CustomizingAndNocode(GspMetadata metadata) {
        String metadataId = metadata.getHeader().getId();
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }

        String code = metadata.getHeader().getCode();
        String nameSpace = metadata.getHeader().getNameSpace();
        String type = metadata.getHeader().getType();

        List<GspMdCustomContent> metadatas = generatedRepoService.getAllByNameSpaceAndCodeAndType(nameSpace, code, type);
        if (!CollectionUtils.isEmpty(metadatas)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0018, nameSpace, code, type);
        }

        if (!StringUtils.isEmpty(code) && !StringUtils.isEmpty(type) && !StringUtils.isEmpty(nameSpace)) {
            List<Metadata4Ref> rtMetadatas = getMetadataListByFilter(new MetadataFilter(code, type, nameSpace, SourceTypeEnum.MDPKG));
            if (!CollectionUtils.isEmpty(rtMetadatas)) {
                throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0014, nameSpace, code, type);
            }
        }

        List<GspMdContent> customMetadatas = repoService.getMetadataInfos(nameSpace, code, type);
        if (!CollectionUtils.isEmpty(customMetadatas)) {
            customMetadatas.forEach(item -> {
                if (!item.getMetadataId().equals(metadataId)) {
                    throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0019, nameSpace, code, type);
                }
            });
        }

    }

    public void metadataSaveCheck4Generated(GspMetadata metadata) {
        String metadataId = metadata.getHeader().getId();
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }

        String code = metadata.getHeader().getCode();
        String nameSpace = metadata.getHeader().getNameSpace();
        String type = metadata.getHeader().getType();

        if (!StringUtils.isEmpty(code) && !StringUtils.isEmpty(type) && !StringUtils.isEmpty(nameSpace)) {
            List<Metadata4Ref> rtMetadatas = getMetadataListByFilter(new MetadataFilter(code, type, nameSpace, SourceTypeEnum.MDPKG));
            if (!CollectionUtils.isEmpty(rtMetadatas)) {
                throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0014, nameSpace, code, type);
            }
        }

        List<GspMdContent> customMetadatas = repoService.getMetadataInfos(nameSpace, code, type);
        if (!CollectionUtils.isEmpty(customMetadatas)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0019, nameSpace, code, type);
        }

        List<GspMdCustomContent> metadatas = generatedRepoService.getAllByNameSpaceAndCodeAndType(nameSpace, code, type);
        if (!CollectionUtils.isEmpty(metadatas)) {
            for (GspMdCustomContent gspMdCustomContent : metadatas) {
                if (!metadataId.equals(gspMdCustomContent.getId())) {
                    throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0018, nameSpace, code, type);
                }
            }
        }
    }

    public void buildBasicMetadataInfo(DimensionExtendEntity dimExtendEntity) {
        //判断基础元数据有无信息，没有的话则获取，有则直接返回
        //if(dimExtendEntity.getBasicMetadataId() != null && !dimExtendEntity.getBasicMetadataId().isEmpty())
        if (!StringUtils.isEmpty(dimExtendEntity.getBasicMetadataId())) {
            return;
        }
        GspMdExtRelation relation = extRelationRepoService.getExtRelationByExtMdInfo(dimExtendEntity.getExtendMetadataEntity().getHeader().getId(), dimExtendEntity.getExtendMetadataEntity().getHeader().getCertId());
        if (relation == null) {
            return;
        }
        dimExtendEntity.setBasicMetadataId(relation.getBasicMdId());
        dimExtendEntity.setBasicMetadataNamespace(relation.getBasicMdNameSpace());
        dimExtendEntity.setBasicMetadataCode(relation.getBasicMdCode());
        dimExtendEntity.setBasicMetadataTypeStr(relation.getBasicMdType());
    }

    public void saveEffectedExtRelationAndMetadata(ArrayList<ExtRelationAndMetadata> effectedExtRelationAndMetadata) {
        for (ExtRelationAndMetadata item : effectedExtRelationAndMetadata) {
            GspMetadata extendMetadata = item.getMetadata();
            GspMdExtRelation extRelation = item.getExtRelation();
            repoService.saveExtContent(extendMetadata);
            RemoveDistCache(extendMetadata.getHeader().getId());
            extRelationRepoService.save(extRelation);
            if (!ObjectUtils.isEmpty(item.getChangeSet())) {
                changesetRepoService.saveChangeSet(item.getChangeSet());
            }
        }
    }

    /**
     * 删除扩展的元数据
     *
     * @param metadataId 扩展元数据ID
     * @param certId     扩展元数据证书
     */
    @Override
    public void deleteExtMetadata(String metadataId, String certId) {
        //删除前校验
        GspMetadata metadata = getMetadataByIdAndCertId(metadataId, certId);
        if (Objects.isNull(metadata)) {
            return;
        }
        deleteCheck(metadataId, certId);
        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            //此处支持更多选项
            tran.begin(TransactionPropagation.REQUIRED);
            fireMetadataDeletingEvent(metadata);
            //如果不存在自身的扩展，允许删除，删除扩展内容，同时删除扩展关系
            repoService.deleteCustomizedData(metadataId, certId);
            extRelationRepoService.deleteExtRelationByMdIdAndCertId(metadataId, certId);
            generatedRepoService.deleteRefs(metadataId);
            mdRtRepoService.deleteMdRtContent(metadata);
            changesetRepoService.deleteChangeSet(metadataId);

            fireMetadataDeletedEvent(metadata);

            RemoveDistCache(metadataId);
            RemoveRtDistCache(metadataId);
            tran.commit();
        } catch (Throwable e) {
            try {
                tran.rollback();
            } catch (Exception ex) {
                log.error("deleteExtMetadata rollback error", ex);
            }
            throw e;
        }
    }

    public void deleteCheck(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        //TODO 删除场景版本也是需要的
        //删除时进行删除检查：查找是否存在扩展元数据，如果存在，不允许删除，提示存在扩展，需要移除扩展后删除
        var relations = extRelationRepoService.getExtRelationByBasicMdIdAndCertId(metadataId, certId);
        //检查当前元数据是否被依赖
        var refs = generatedRepoService.getMdRefsByRefMdId(metadataId);
        if (relations != null && relations.size() > 0) {
            StringBuilder sb = new StringBuilder();
            relations.forEach(item -> {
                sb.append("MetadataID: ").append(item.getExtMdId())
                        .append(", Code: ").append(item.getExtMdCode())
                        .append("; ");
            });
            throw new LcmMetadataCustomizationException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0005, metadataId, sb.toString());
        }
        if (refs != null && refs.size() > 0) {
            StringBuilder sb = new StringBuilder();
            refs.forEach(item -> {
                sb.append("MetadataID: ").append(item.getMdId())
                        .append(", Code: ").append(item.getMdCode())
                        .append("; ");
            });
            throw new LcmMetadataCustomizationException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0012, metadataId, sb.toString());
        }
    }

    @Override
    public void deleteGeneratedMetadata(String metadataId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        //TODO 删除场景版本也是需要的
        //删除时进行删除检查：查找是否存在扩展元数据，如果存在，不允许删除，提示存在扩展，需要移除扩展后删除
        List<GspMdExtRelation> relations = extRelationRepoService.getExtRelationByBasicMdIdAndCertId(metadataId, null);
        //检查当前元数据是否被依赖
        List<GspMdRefs> refs = generatedRepoService.getMdRefsByRefMdId(metadataId);
        if (relations != null && relations.size() > 0) {
            StringBuilder sb = new StringBuilder();
            relations.forEach(item -> {
                sb.append("MetadataID: ").append(item.getExtMdId())
                        .append(", Code: ").append(item.getExtMdCode())
                        .append("; ");
            });
            throw new LcmMetadataCustomizationException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0005, metadataId, sb.toString());
        }
        if (refs != null && refs.size() > 0) {
            StringBuilder sb = new StringBuilder();
            refs.forEach(item -> {
                sb.append("MetadataID: ").append(item.getMdId())
                        .append(", Code: ").append(item.getMdCode())
                        .append("; ");
            });
            throw new LcmMetadataCustomizationException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0012, metadataId, sb.toString());
        }

        GspMdCustomContent md = generatedRepoService.findByMetadataId(metadataId);
        if (md == null) {
            return;
        }
        // 如果是文件化，并且上下文中有租户信息，增加租户越权校验
        if (MetadataStorageUtils.isUsingSecondDatasource() && CAFContext.current.getTenantId() != -1) {
            // 如果元数据的tenantId为null，说明是共享元数据，不允许删除。
            // 如果元数据的tenantId和上下文中的不一样，说明是别的租户的元数据，不允许删除。
            if (md.getTenantId() == null || md.getTenantId() != CAFContext.current.getTenantId()) {
                throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0023, md.getName());
            }
        }
        JpaTransaction tran = MetadataStorageUtils.getTransaction();
        try {
            //此处支持更多选项
            tran.begin(TransactionPropagation.REQUIRED);
            GspMetadata metadata = new GspMetadata(new MetadataHeader(md.getId(), md.getNameSpace(), md.getCode(), md.getName(), md.getType(), md.getBizObjId()));
            fireMetadataDeletingEvent(metadata);

            generatedRepoService.deleteGeneratedMetadata(metadataId);
            metadataRefsRepoService.deleteByMdId(metadataId);

            fireMetadataDeletedEvent(metadata);

            RemoveDistCache(metadataId);
            RemoveRtDistCache(metadataId);
            tran.commit();
        } catch (Throwable e) {
            try {
                tran.rollback();
            } catch (Exception ex) {
                log.error("deleteGeneratedMetadata rollback error", ex);
            }
            throw new LcmMetadataCustomizationException(e, ErrorCodes.ECP_METADATA_CUSTOMIZATION_0006, metadataId);
        }
    }

    /**
     * 判断某维度值下，是否已经存在扩展的元数据
     */
    @Override
    public boolean isExistExtendObjectWithDims(String basicMetadataID, String basicMetadataCertId,
        String firstDimension, String secondDimension) {
        if (StringUtils.isEmpty(basicMetadataID)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "basicMetadataID");
        }
        //从扩展关系表中查询是否存在某个维度的扩展
        var relation = extRelationRepoService.getRelationByDims(basicMetadataID, basicMetadataCertId, firstDimension, secondDimension);
        return relation != null;
    }

    /**
     * 此方法为将指定的元数据发布，仅考虑分层扩展的元数据会合并发布为同一元数据 按照维度扩展的元数据不考虑找出来并进行合并
     */
    @Override
    public boolean releaseMetadataToRt(String metadataId, String certId) {
        return releaseMetadataToRtWithSourceType(metadataId, certId, SourceTypeEnum.CUSTOMIZED.name());
    }

    @Override
    public boolean releaseMetadataToRtWithSourceType(String metadataId, String certId, String sourceType) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        // 保存到dt表时已经有了保存前后事件，保存到rt表就不需要了
        //将元数据从设计时表 发布到 运行时表
        GspMetadata metadata = repoService.getCurrentMetadata(metadataId, certId);
        GspMetadata needToReleaseMetadata = getNeedToReleaseMetadata(metadata);

        // TODO 更新依赖关系
        List<GspMdRefs> gspMdRefs = metadataRefsRepoService.buildGspMdRefsByMetadata(needToReleaseMetadata);

        JpaTransaction tran = JpaTransaction.getTransaction();
        try{
            tran.begin();
            metadataRefsRepoService.deleteByMdId(needToReleaseMetadata.getHeader().getId());
            metadataRefsRepoService.saveAll(gspMdRefs);
            mdRtRepoService.saveMdRtContent(needToReleaseMetadata, SourceTypeEnum.valueOf(sourceType));
            tran.commit();
        } catch (Throwable e) {
            try {
                tran.rollback();
            } catch (Exception ex) {
                log.error("releaseMetadataToRtWithSourceType rollback error", ex);
            }
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0013, needToReleaseMetadata.getHeader().getId(), needToReleaseMetadata.getHeader().getNameSpace(), needToReleaseMetadata.getHeader().getCode());
        }

        //修改运行时定制发布元数据时，缓存失效处理。不要往缓存中放元数据。获取元数据客户端有同步逻辑（vo同步be内容），会更新缓存。如果此处放了缓存内容，不会走到同步逻辑。
        MetadataRtDistCache.remove(RtCacheHandler.getMetadataCacheKey(metadataId, RuntimeContext.getLanguage()));
        MetadataRtDistCache.remove(RtCacheHandler.getMetadataCacheKey(metadataId, ""));
        return true;
    }

    /**
     * 根据扩展元数据找到根基础元数据getMetadataInfoRecusively
     */
    @Override
    public MetadataDto getBasicMetadataByExtMdId(String metadataId, String certId) {
        GspMetadata metadata = getBasicMdByExtMdId(metadataId, certId);
        return MetadataDtoConverter.asDto(metadata);
    }
    /**
     * 根据扩展元数据Id找到根基础元数据Id
     */
    @Override
    public String getBasicMetadataIdByExtMdId(String metadataId, String certId) {
        return getBasicMdIdByExtMdId(metadataId, certId);
    }

    private GspMetadata getBasicMdByExtMdId(String metadataId, String certId) {
        GspMdExtRelation relation = extRelationRepoService.getExtRelationByExtMdIdAndCertId(metadataId, certId);
        if (relation == null) {
            return getMetadataByIdAndCertId(metadataId, certId);
        } else {
            return getBasicMdByExtMdId(relation.getBasicMdId(), relation.getBasicMdCertId());
        }
    }

    /**
     * 根据扩展元数据id查找基础元数据id
     * @param metadataId
     * @param certId
     * @return
     */
    private String getBasicMdIdByExtMdId(String metadataId, String certId) {
        GspMdExtRelation relation = extRelationRepoService.getExtRelationByExtMdIdAndCertId(metadataId, certId);
        if (relation == null) {
            return metadataId;
        } else {
            return getBasicMdIdByExtMdId(relation.getBasicMdId(), relation.getBasicMdCertId());
        }
    }

    @Override
    public Metadata4Ref getBasicPkgMetadataByExtMdId(String metadataId, String certId) {
        GspMdExtRelation relation = extRelationRepoService.getExtRelationByExtMdIdAndCertId(metadataId, certId);
        if (relation == null) {
            return mdRtRepoService.getPkgMetadataByMetadataId(metadataId);
        } else {
            return getBasicPkgMetadataByExtMdId(relation.getBasicMdId(), relation.getBasicMdCertId());
        }

    }


    @Override
    public GspMdChangeset getChangeset(String metadataId, String certId, String version) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        return changesetRepoService.getChangeset(metadataId, certId, version);
    }

    /**
     * 获取所有的指定类型的运行时定制元数据
     */
    @Override
    public List<Metadata4Ref> getAllCustomizedMetadataInfoWithTypes(String metadataTypes) {
        if (metadataTypes == null || metadataTypes.isEmpty()) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataTypes");
        }
        return repoService.getAllCustomizedMetadata(metadataTypes);
    }

    @Override
    public List<Metadata4Ref> getAllGeneratedMdInfoWithTypes(String metadataTypes) {
        return generatedRepoService.getAllRTGeneratedMetadata(metadataTypes);
    }

    @Override
    public List<Metadata4Ref> getAllOriginMdInfoWithTypes(String metadataTypes) {
        List<Metadata4Ref> result = new ArrayList<>();
        List<Metadata4Ref> metadatas;
        List<Metadata4Ref> packagedMetadatas;
        if (metadataTypes == null || metadataTypes.length() <= 0) {
            packagedMetadatas = mdRtRepoService.getMdpkgMetadata4RefList(null);
            metadatas = generatedRepoService.getAllRTGeneratedMetadata();
        } else {
            String[] types = metadataTypes.split(",");
            List<String> typeList = new ArrayList<>(Arrays.asList(types));
            packagedMetadatas = mdRtRepoService.getMdpkgMetadata4RefList(typeList);
            metadatas = generatedRepoService.getAllRTGeneratedMetadata(metadataTypes);
        }
        if (packagedMetadatas != null && packagedMetadatas.size() > 0) {
            result.addAll(packagedMetadatas);
        }
        if (metadatas != null && metadatas.size() > 0) {
            result.addAll(metadatas);
        }
        return result;
    }

    @Override
    public List<Metadata4Ref> getMetadataInfoByFilter(MetadataRTFilter filter) {
        List<Metadata4Ref> packagedMetdataList = getMetadataListByFilter(new MetadataFilter(SourceTypeEnum.MDPKG, null));
        packagedMetdataList = filterMetadata(packagedMetdataList, filter);
        List<Metadata4Ref> generatedMetadatalist = filterMetadata(generatedRepoService.getAllRTGeneratedMetadata(), filter);
        List<Metadata4Ref> customizedMetadatalist = filterMetadata(repoService.getAllCustomizedMetadata(), filter);
        List<Metadata4Ref> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(packagedMetdataList)) {
            result.addAll(packagedMetdataList);
        }
        if (!CollectionUtils.isEmpty(generatedMetadatalist)) {
            result.addAll(generatedMetadatalist);
        }
        if (!CollectionUtils.isEmpty(customizedMetadatalist)) {
            result.addAll(customizedMetadatalist);
        }
        return result;
    }

    private List<Metadata4Ref> filterMetadata(List<Metadata4Ref> metadataList, MetadataRTFilter filter) {
        if (CollectionUtils.isEmpty(metadataList)) {
            return null;
        }
        // 根据AppCode进行过滤
        if (filter.getAppCode() != null) {
            metadataList = metadataList.stream().filter(item -> item.getServiceUnitInfo() == null || filter.getAppCode().equalsIgnoreCase(item.getServiceUnitInfo().getAppCode())).collect(Collectors.toList());
        }
        // 根据ServiceUnitCode进行过滤
        if (filter.getServiceUnitCode() != null) {
            metadataList = metadataList.stream().filter(item -> item.getServiceUnitInfo() == null || filter.getServiceUnitCode().equalsIgnoreCase(item.getServiceUnitInfo().getServiceUnitCode())).collect(Collectors.toList());
        }
        // 根据BizobjectID进行过滤
        if (filter.getBizobjectId() != null && filter.getBizobjectId().size() > 0) {
            for (String eachBizobjectId : filter.getBizobjectId()) {
                metadataList = metadataList.stream().filter(item -> eachBizobjectId.equals(item.getMetadata().getHeader().getBizobjectID())).collect(Collectors.toList());
            }
        }
        if (filter.getCode() != null) {
            metadataList = metadataList.stream().filter(item -> item.getMetadata().getHeader().getCode() != null && filter.getCode().equals(item.getMetadata().getHeader().getCode())).collect(Collectors.toList());
        }
        if (filter.getNameSpace() != null) {
            metadataList = metadataList.stream().filter(item -> item.getMetadata().getHeader().getNameSpace() != null && item.getMetadata().getHeader().getNameSpace().equals(filter.getNameSpace())).collect(Collectors.toList());
        }
        if (filter.getType() != null) {
            metadataList = metadataList.stream().filter(item -> item.getMetadata().getHeader().getType() != null && item.getMetadata().getHeader().getType().equals(filter.getType())).collect(Collectors.toList());
        }
        return metadataList;
    }

    @Override
    public List<Metadata4Ref> getAllPackagedMetadataInfo() {
        return getMetadataListByFilter(new MetadataFilter(SourceTypeEnum.MDPKG, null));
    }

    @Override
    public List<Metadata4Ref> getAllPackagedMetadataInfoWithTypes(String metadataTypes) {
        List<String> typeList = StringUtils.isEmpty(metadataTypes) ? null : new ArrayList<>(Arrays.asList(metadataTypes.split(",")));
        return getMetadataListByFilter(new MetadataFilter(SourceTypeEnum.MDPKG, typeList));
    }

    private GspMetadata getNeedToReleaseMetadata(GspMetadata metadata) {
        //TODO 正常情况下需要获取元数据的分层扩展关系，然后合并
        return metadata;
    }

    /**
     * 根据要更新的基础元数据，进行冲突检查，冲突检查要检查合并冲突
     *
     * @param manager                        基础层次元数据，内容需要往下合并，具体合并冲突只能合并时发现
     * @param preversionMetadata             迁移版本元数据
     * @param change                         当前元数据与上一版本元数据的变更
     * @param effectedExtRelationAndMetadata 影响的元数据列表
     * @param rootMetadata                   扩展的基元数据
     */
    private void validateMetadataMergeConflict(CustomizationExtHandler manager, GspMetadata preversionMetadata,
        AbstractCustomizedContent change, ArrayList<ExtRelationAndMetadata> effectedExtRelationAndMetadata,
        GspMetadata rootMetadata, List<GspMdExtRelation> extRelations) {
        //受影响的内容集合，最后可以用来保存
        preMergeChangesFrmParentAndRecordContent(manager, preversionMetadata, change, effectedExtRelationAndMetadata, rootMetadata, extRelations);

    }

    private void preMergeChangesFrmParentAndRecordContent(CustomizationExtHandler manager,
        GspMetadata preversionMetadata, AbstractCustomizedContent content,
        ArrayList<ExtRelationAndMetadata> effectedExtRelationAndMetadata, GspMetadata rootMetadata,
        List<GspMdExtRelation> extRelations) {
        for (GspMdExtRelation item : extRelations) {
            //根据扩展关系中记录的元数据，找到当前版本元数据
            GspMetadata currentMd = repoService.getCurrentMetadata(item.getExtMdId(), item.getExtMdCertId());
            //尝试与上级增量合并，形成新内容元数据，并且版本 +1
            //合并如果出错，本次保存过程终止
            AbstractCustomizedContent changeToParent = getChangeToParent(currentMd.getHeader().getId(), currentMd.getHeader().getCertId(), currentMd.getVersion());
            AbstractCustomizedContent mergedContent = manager.changeMerge(new ChangeMergeArgs(content, changeToParent, rootMetadata, preversionMetadata, currentMd));
            if (ObjectUtils.isEmpty(mergedContent)) {
                continue;
            }
            GspMetadata newVersionMd = manager.merge(new MetadataMergeArgs(currentMd, mergedContent, rootMetadata));
            newVersionMd.setVersion(String.valueOf(Integer.parseInt(currentMd.getVersion()) + 1));
            newVersionMd.setPreviousVersion(currentMd.getVersion());

            GspMdChangeset changeSet = changesetRepoService.getChangeset(currentMd.getHeader().getId(), currentMd.getHeader().getCertId(), currentMd.getVersion());
            if (!ObjectUtils.isEmpty(changeSet)) {
                changeSet.setVersion(String.valueOf(Integer.parseInt(currentMd.getVersion()) + 1));
                newVersionMd.setPreviousVersion(currentMd.getVersion());
            }

            //更新扩展关系中的版本，并且将新关系与新元数据组合，并且记录
            ExtRelationAndMetadata relationAndMetadata = buildDimensionExtendEntityInMergeProcess(item, newVersionMd, changeSet);
            effectedExtRelationAndMetadata.add(relationAndMetadata);
            AbstractCustomizedContent change = manager.getExtContent(new ExtContentArgs(currentMd, newVersionMd, rootMetadata));
            List<GspMdExtRelation> relations = extRelationRepoService.getExtRelationByBasicMdIdAndCertId(currentMd.getHeader().getId(), currentMd.getHeader().getCertId());
            if (!CollectionUtils.isEmpty(relations)) {
                preMergeChangesFrmParentAndRecordContent(manager, currentMd, change, effectedExtRelationAndMetadata, rootMetadata, relations);
            }
        }
    }

    public AbstractCustomizedContent getChangeToParent(String metadataId, String certId, String version) {

        GspMdChangeset response = this.getChangeset(metadataId, certId, version);
        return utils.buildAbstractCustomizdContet(response);
    }

    private ExtRelationAndMetadata buildDimensionExtendEntityInMergeProcess(GspMdExtRelation item,
        GspMetadata newVersionMd, GspMdChangeset changeSet) {

        //当前传入的扩展关系是之前的扩展关系，扩展关系中基础元数据版本 是原有版本，扩展元数据版本也是原有版本，版本应该做+1处理
        GspMdExtRelation mdExtRelation = new GspMdExtRelation();
        mdExtRelation.setId(UUID.randomUUID().toString());
        mdExtRelation.setBasicMdId(item.getBasicMdId());
        mdExtRelation.setBasicMdCertId(item.getBasicMdCertId());
        try {
            int basicMdVersion = Integer.parseInt(item.getBasicMdVersion());
            mdExtRelation.setBasicMdVersion(String.valueOf(basicMdVersion + 1));
        } catch (NumberFormatException e) {
            mdExtRelation.setBasicMdVersion("1");
        }
        mdExtRelation.setBasicMdCode(item.getBasicMdCode());
        mdExtRelation.setBasicMdNameSpace(item.getBasicMdNameSpace());
        mdExtRelation.setBasicMdType(item.getBasicMdType());
        mdExtRelation.setExtMdId(item.getExtMdId());
        mdExtRelation.setExtMdCertId(item.getExtMdCertId());
        mdExtRelation.setExtMdCode(item.getExtMdCode());
        mdExtRelation.setExtMdNameSpace(item.getExtMdNameSpace());
        mdExtRelation.setExtMdType(item.getExtMdType());
        mdExtRelation.setFirstDimName(item.getFirstDimName());
        mdExtRelation.setFirstDimCode(item.getFirstDimCode());
        mdExtRelation.setSecDimName(item.getSecDimName());
        mdExtRelation.setSecDimCode(item.getSecDimCode());
        try {
            int extMdVersion = Integer.parseInt(item.getExtMdVersion());
            mdExtRelation.setExtMdVersion(String.valueOf(extMdVersion + 1));
        } catch (NumberFormatException e) {
            mdExtRelation.setExtMdVersion("1");
        }
        mdExtRelation.setSecDimValue(item.getSecDimValue());
        mdExtRelation.setFirstDimValue(item.getFirstDimValue());
        //mdextRelation 与 newversionmd是需要重新保存的内容，影响的元数据新版版，影响的依赖关系。
        ExtRelationAndMetadata relationAndMetadata = new ExtRelationAndMetadata();
        relationAndMetadata.setExtRelation(mdExtRelation);
        relationAndMetadata.setMetadata(newVersionMd);
        relationAndMetadata.setChangeSet(changeSet);

        return relationAndMetadata;
    }

    //endregion

    /**
     * 获取所有定制的元数据信息，包括运行时新建的元数据
     */
    @Override
    public List<Metadata4Ref> getAllCustomizedMetadataInfo() {
        //直接从定制元数据表中查询元数据信息
        return repoService.getAllCustomizedMetadata();
    }

    @Override
    public List<Metadata4Ref> getAllGeneratedMetadataInfo() {
        return generatedRepoService.getAllRTGeneratedMetadata();
    }

    @Override
    public List<DimensionExtendEntity> getMetadataInfoListRecusively(String basicMetadataId,
        String basicMetadataCertId) {
        if (StringUtils.isEmpty(basicMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "basicMetadataId");
        }
        List<DimensionExtendEntity> infos = new ArrayList<>();
        getMetaInfoRecusively(basicMetadataId, basicMetadataCertId, infos);
        return infos;
    }

    private void getExtrelationsRecusively(String basicMetadataId, String basicMetadataCertId,
        List<GspMdExtRelation> extRelationList) {
        var relations = extRelationRepoService.getExtRelationByBasicMdInfo(basicMetadataId, basicMetadataCertId);
        if (relations == null) {
            return;
        }
        extRelationList.addAll(relations);
        relations.forEach(item -> {
            getExtrelationsRecusively(item.getExtMdId(), item.getExtMdCertId(), extRelationList);
        });
    }

    private void getMetaInfoRecusively(String basicMetadataId, String basicMetadataCertId,
        List<DimensionExtendEntity> metadataList) {
        var relations = extRelationRepoService.getExtRelationByBasicMdInfo(basicMetadataId, basicMetadataCertId);
        if (relations == null) {
            return;
        }
        relations.forEach(item -> {
            getMetaInfoRecusively(item.getExtMdId(), item.getExtMdCertId(), metadataList);
            var metadata = getCustomizdMetadataListByIdAndCertId(item.getExtMdId(), item.getExtMdCertId(), item.getExtMdVersion());
            if (metadata == null) {
                throw new LcmMetadataCustomizationException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0004, basicMetadataId, item.getExtMdId(), item.getId());
            }
            metadataList.add(metadata);
        });
    }

    public DimensionExtendEntity getCustomizdMetadataListByIdAndCertId(String id, String certid, String version) {
        var customizedMetadatas = repoService.getCustomizedListByIdAndCertId(id, certid, version);
        if (CollectionUtils.isEmpty(customizedMetadatas)) {
            return null;
        }
        var relation = extRelationRepoService.getExtRelationByExtMdInfo(customizedMetadatas.get(0).getMetadataId(), customizedMetadatas.get(0).getCertId());

        return buildDimensionExtendEntity(customizedMetadatas.get(0), relation);
    }

    private DimensionExtendEntity buildDimensionExtendEntity(GspMdContent mdContent, GspMdExtRelation relation) {
        DimensionExtendEntity extendEntity = new DimensionExtendEntity();
        extendEntity.setFirstDimension(relation.getFirstDimValue());
        extendEntity.setSecondDimension(relation.getSecDimValue());
        extendEntity.setBasicMetadataId(relation.getBasicMdId());
        extendEntity.setBasicMetadataCertId(relation.getBasicMdCertId());
        extendEntity.setBasicMetadataCode(relation.getBasicMdCode());
        extendEntity.setBasicMetadataNamespace(relation.getBasicMdNameSpace());
        extendEntity.setBasicMetadataVersion(relation.getBasicMdVersion());
        extendEntity.setBasicMetadataTypeStr(relation.getBasicMdType());
        extendEntity.setFirstDimensionName(relation.getFirstDimName());
        extendEntity.setFirstDimensionCode(relation.getFirstDimCode());
        extendEntity.setSecondDimensionName(relation.getSecDimName());
        extendEntity.setSecondDimensionCode(relation.getSecDimCode());
        GspMetadata metadata = repoService.buildMetadata4RefFromGspMdContent(mdContent);
        extendEntity.setExtendMetadataEntity(metadata);
        return extendEntity;
    }

    @Override
    public void save(MetadataDto metadataDto) {
        if (Objects.isNull(metadataDto)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataDto");
        }
        GspMetadata metadata = MetadataDtoConverter.asMetadata(metadataDto);
        saveGeneratedMetadata(metadata);
    }

    @Override
    public MetadataDto saveMetadata(MetadataDto metadataDto) {

        GspMetadata metadata = MetadataDtoConverter.asMetadata(metadataDto);

        if (metadata == null || metadata.getHeader() == null || metadata.getContent() == null) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadata");
        }

        //1. 元数据校验
        metadataSaveCheck(metadata);

        //2. 执行保存
        saveCustomizedGspMetadata(metadata);

        //3. 清理缓存
        RemoveDistCache(metadata.getHeader().getId());

        return MetadataDtoConverter.asDto(metadata);

    }

    @Transactional
    public void saveCustomizedGspMetadata(GspMetadata metadata) {
        //更新元数据版本
        updateMetadaVersion(metadata);

        //构造GspMdContent，需要设置sourceType
        GspMdContent mdContent = repoService.buildGspMdContentFromGspMetdata(metadata, metadata.getHeader().getId(), false);

        // 保存前设置设置sourceType
        mdContent.setSourceType(DtSourceTypeEnum.CUSTOMIZING.getCode());
        mdContentRepo.save(mdContent);
    }

    @Override
    public void saveGeneratedMetadata(GspMetadata metadata) {
        if (metadata == null || metadata.getHeader() == null || metadata.getContent() == null) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadata");
        }
        metadataSaveCheck4Generated(metadata);
        buildMetadataRef(metadata);
        List<GspMdRefs> metadataRefs = metadataRefsRepoService.buildGspMdRefsByMetadata(metadata);

        fireMetadataSavingEvent(metadata, ProcessMode.interpretation);
        fireGeneratedMetadataSavingEvnet(metadata);

        JpaTransaction tran = MetadataStorageUtils.getTransaction();
        try {
            //此处支持更多选项
            tran.begin(TransactionPropagation.REQUIRED);
            generatedRepoService.saveMetadata(metadata);
            // TODO 更新依赖关系
            metadataRefsRepoService.deleteByMdId(metadata.getHeader().getId());
            metadataRefsRepoService.saveAll(metadataRefs);
            tran.commit();
        } catch (Throwable e) {
            try {
                tran.rollback();
            } catch (Exception ex) {
                log.error("saveGeneratedMetadata rollback error", ex);
            }
            throw new LcmMetadataException(e, ErrorCodes.ECP_METADATA_0013, metadata.getHeader().getId(), metadata.getHeader().getNameSpace(), metadata.getHeader().getCode());
        }

        fireMetadataSavedEvent(metadata, ProcessMode.interpretation);
        fireGeneratedMetadataSavedEvent(metadata);

        RemoveRtDistCache(metadata.getHeader().getId());
        RemoveDistCache(metadata.getHeader().getId());
    }

    public GspMetadata buildMetadataRef(GspMetadata metadata) {
        //TODO:考虑添加依赖关系是否变更标志，现在每次都需要获取依赖关系保存
        //构造元数据依赖关系
        IMetadataRtReferenceManager refManager = ReferenceHelper.getInstance().getManager(metadata.getHeader().getType());
        if (refManager != null) {
            var refsCollection = refManager.getConstraint(metadata);
            metadata.setRefs(refsCollection);
        }

        return metadata;
    }

    public MetadataDto getMetadataDtoById(String metadataId, String certId) {
        GspMetadata metadata = getMetadataByIdAndCertId(metadataId, certId);
        return MetadataDtoConverter.asDto(metadata);
    }

    public GspMetadata getMetadataByIdAndCertId(String metadataId, String certId) {
        //先从缓存中获取元数据内容，有内容直接返回；无内容进行加载
        //从扩展关系表中查询是否存在扩展关系
        //如果不存在扩展关系，属于非扩展元数据，直接从包中加载或者从数据库中加载
        //如果存在扩展关系，获取当前版本元数据返回
        GspMetadata metadata;
        String language = RuntimeContext.getLanguage();
        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadataId, language);
        metadata = MetadataDistCacheManager.get(metadataKey);
        if (metadata != null) {
            return metadata;
        }
        //根据元数据id，从扩展关系表中，找不到此元数据是从基础元数据扩展的，按照正常元数据加载
        metadata = mdRtRepoService.getMetadataByIdSourceType(metadataId, SourceTypeEnum.MDPKG.getCode());
        if (metadata != null) {
            MetadataDistCacheManager.put(metadataKey, metadata, null);
            return metadata;
        }

        metadata = generatedRepoService.getMetadata(metadataId);
        if (metadata != null) {
            MetadataDistCacheManager.put(metadataKey, metadata, null);
            return metadata;
        }

        metadata = repoService.getCurrentMetadata(metadataId, certId);
        if (metadata != null) {
            MetadataDistCacheManager.put(metadataKey, metadata, null);
        }
        return metadata;
    }

    @Override
    public boolean isMdDeletable(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        //TODO 删除场景版本也是需要的
        //删除时进行删除检查：查找是否存在扩展元数据，如果存在，不允许删除，提示存在扩展，需要移除扩展后删除
        var relations = extRelationRepoService.getExtRelationByBasicMdIdAndCertId(metadataId, certId);
        if (!CollectionUtils.isEmpty(relations)) {
            return false;
        }
        //检查当前元数据是否被依赖
        var refs = generatedRepoService.getMdRefsByRefMdId(metadataId);

        return CollectionUtils.isEmpty(refs);
    }

    private MetadataRtEventArgs buildMetadataRtEventArgs(GspMetadata metadata) {
        MetadataRtEventArgs args = new MetadataRtEventArgs();
        args.setMetadata(metadata);
        return args;
    }

    @Override
    public GspMdExtRelation getExtRelationByExtMdIdAndCertId(String extMetadataId, String extMdCertId) {
        return extRelationRepoService.getExtRelationByExtMdIdAndCertId(extMetadataId, extMdCertId);
    }

    @Override
    public GspMdChangeset getChangeset(String metadataId, String certId) {
        return changesetRepoService.getChangeset(metadataId, certId);
    }

    @Override
    public void saveMetadataExtRelation(GspMdExtRelation extRelation) {
        extRelationRepoService.save(extRelation);
    }

    @Override
    public void saveMdChangeSet(GspMdChangeset changeSet) {
        changesetRepoService.save(changeSet);
    }

    @Override
    public void afterMetadataChanged() {}

    @Override
    public void initMetadataCache() {}

    @Override
    public void clearAllCache() {
        MetadataDistCacheManager.getMetadataCache().clear();
        MetadataRtDistCache.getMetadataCache().clear();
    }

    /**
     * 根据根元数据id和维度值获取元数据信息 如果不存在相应维度值的扩展，根据扩展关系获取基础维度的扩展元数据，直至获取对应的产品元数据
     *
     * @param rootMetadataId       基础元数据ID
     * @param rootMetadataCertId   基础元数据证书id
     * @param firstDimensionValue  第一维度值
     * @param secondDimensionValue 第二维度值
     * @return 元数据传输实体 metadataDto
     */
    @Override
    public MetadataDto getDynamicMetadataWithRootMdIdAndDimensions(String rootMetadataId,
        String rootMetadataCertId, String firstDimensionValue, String secondDimensionValue) {
//        在使用运行时定制的过程中，产品开发人员不确定是否项目上存在扩展元数据。
//        产品开发人员写处理代码的时候，传入具体的产品元数据id，事先定义好的维度值信息，然后判断是否能够找到扩展元数据，直至获取对应的产品元数据
        if (StringUtils.isEmpty(rootMetadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "rootMetadataId");
        }
        List<GspMdExtRelation> relations = new ArrayList<>();
        getExtrelationsRecusively(rootMetadataId, rootMetadataCertId,relations);
        //未获取到扩展元数据，应该返回根元数据
        if (CollectionUtils.isEmpty(relations)){
            return getMetadataDtoById(rootMetadataId, rootMetadataCertId);
        }
        else{
            //根据传入的维度值过滤元数据
            //传入的维度均为空，返回根元数据或者公共扩展元数据
            if (StringUtils.isEmpty(firstDimensionValue) && StringUtils.isEmpty(secondDimensionValue)){
                GspMdExtRelation relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getFirstDimValue()) && StringUtils.isEmpty(item.getSecDimValue())).findAny().orElse(null);
                if (Objects.isNull(relation)){
                    return getMetadataDtoById(rootMetadataId, rootMetadataCertId);
                }
                else{
                    return getMetadataDtoById(relation.getExtMdId(), relation.getExtMdCertId());
                }
            }
            //传入的维度1值非空，维度2值空，返回维度1值元数据或者公共扩展元数据或者根元数据
            if (!StringUtils.isEmpty(firstDimensionValue) && StringUtils.isEmpty(secondDimensionValue)){
                GspMdExtRelation relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getSecDimValue()) && firstDimensionValue.equals(item.getFirstDimValue())).findAny().orElse(null);
                if (Objects.isNull(relation)){
                    relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getFirstDimValue()) && StringUtils.isEmpty(item.getSecDimValue())).findAny().orElse(null);
                    if (Objects.isNull(relation)){
                        return getMetadataDtoById(rootMetadataId, rootMetadataCertId);
                    }
                    else{
                        return getMetadataDtoById(relation.getExtMdId(), relation.getExtMdCertId());
                    }
                }
                else{
                    return getMetadataDtoById(relation.getExtMdId(), relation.getExtMdCertId());
                }
            }
            //传入的维度1值非空，维度2值非空，返回维度1,2值元数据或者维度1值元数据或者公共元数据或者根元数据
            if (!StringUtils.isEmpty(firstDimensionValue) && !StringUtils.isEmpty(secondDimensionValue)){
                GspMdExtRelation relation = relations.stream().filter(item -> firstDimensionValue.equals(item.getFirstDimValue()) && secondDimensionValue.equals(item.getSecDimValue())).findAny().orElse(null);
                if (Objects.isNull(relation)){
                    relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getSecDimValue()) && firstDimensionValue.equals(item.getFirstDimValue())).findAny().orElse(null);
                    if (Objects.isNull(relation)){
                        relation = relations.stream().filter(item -> StringUtils.isEmpty(item.getFirstDimValue()) && StringUtils.isEmpty(item.getSecDimValue())).findAny().orElse(null);
                        if (Objects.isNull(relation)){
                            return getMetadataDtoById(rootMetadataId, rootMetadataCertId);
                        }
                        else{
                            return getMetadataDtoById(relation.getExtMdId(), relation.getExtMdCertId());
                        }
                    }
                    else{
                        return getMetadataDtoById(relation.getExtMdId(), relation.getExtMdCertId());
                    }
                }
                else {
                    return getMetadataDtoById(relation.getExtMdId(), relation.getExtMdCertId());
                }
            }
            //传入的维度1值空，维度2值非空，实际上不存在这种情况，属于参数异常
            if (StringUtils.isEmpty(firstDimensionValue) && !StringUtils.isEmpty(secondDimensionValue)){
                throw new LcmMetadataCustomizationException(ErrorCodes.ECP_METADATA_CUSTOMIZATION_0002, rootMetadataId, secondDimensionValue);
            }
            return getMetadataDtoById(rootMetadataId, rootMetadataCertId);
        }
    }

    private List<GspMdCustomContent> findAllLastChangedOnFromGspMdCustomContent() {
        return generatedRepoService.findAllLastChangedOn();
    }

    private List<GspMdContent> findAllLastChangedOnFromGspMdContent() {
        return repoService.findAllLastChangedOn();
    }

    @Override
    protected GspMetadata getMetadataFromDb(String metadataId) {
        //1、从运行时表中获取，获取包中的元数据
        GspMetadata metadata = mdRtRepoService.getRtMetadataByMetadataIdAndSourceType(metadataId, SourceTypeEnum.MDPKG);
        if (metadata != null) {
            return metadata;
        }

        //2、从运行时生成的表中获取
        metadata = generatedRepoService.getMetadata(metadataId);
        if (metadata != null) {
            return metadata;
        }

        //3、从运行时定制表中获取，获取包中的元数据、获取运行时定制过程中的元数据
        metadata = repoService.getCurrentMetadata(metadataId, null);
        return metadata;
    }

    @Override
    protected GspMetadata getMetadataFromCache(String metadataId, boolean isI18n) {
        // 如果缓存模式是调试模式，则不用缓存
        if (EnvironmentContext.cacheMode == CacheModeEnum.debug) {
            return null;
        }
        return MetadataDistCacheManager.get(metadataId, isI18n);
    }

    @Override
    protected void putMetadataToCache(String metadataId, GspMetadata metadata, boolean isI18n) {
        String language = isI18n ? RuntimeContext.getLanguage() : "";
        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadataId, language);
        MetadataDistCacheManager.put(metadataKey, metadata, MetadataDistCacheManager.SECOND_CACHE);
    }

    @Override
    protected MetadataStringDto getCustomizedMetadataStringDto(String metadataId) {
        GspMdContent gspMdContent = repoService.findByMetadataId(metadataId);
        if (gspMdContent != null) {
            return new MetadataStringDto(gspMdContent.getContent(), gspMdContent.getLastChangedOn().toString());
        } else {
            return null;
        }
    }
    @Override
    public Metadata4Ref getMetadata4RefById(String metadataId) {
        Metadata4Ref metadata4Ref = generatedRepoService.getRTGeneratedMetadataById(metadataId, true);
        if(metadata4Ref == null) {
            metadata4Ref = mdRtRepoService.getMetadata4RefById(metadataId);
        }
        return metadata4Ref;
    }

    @Override
    public MetadataDto buildResourceMetadata(MetadataDto metadataDto) {
        GspMetadata metadata = MetadataDtoConverter.asMetadata(metadataDto);
        I18nResource resouceItem = getResouceItem(metadata);
        // 判断是否存在资源元数据
        MetadataReference resourceMetatadaRef = MetadataCustomizationUtils.findResourceMetatadaRef(metadata);

        String resourceMetadataFileName = getResourceMetadataFileName(metadata);
        GspMetadata resourceMetadata = null;
        if (resourceMetatadaRef != null) {
            // 查询md表
            resourceMetadata = repoService.getCurrentMetadata(resourceMetatadaRef.getDependentMetadata().getId(), resourceMetatadaRef.getDependentMetadata().getCertId());
        }

        if(resourceMetadata == null) {
            resourceMetadata = new GspMetadata();
            MetadataHeader header = new MetadataHeader();
            header.setId(UUID.randomUUID().toString());
            FileServiceImp fileService = new FileServiceImp();
            String fileNameWithoutExtension = fileService.getFileNameWithoutExtension(resourceMetadataFileName);
            header.setCode(fileNameWithoutExtension);
            header.setName(fileNameWithoutExtension);
            header.setFileName(resourceMetadataFileName);
            header.setNameSpace(metadata.getHeader().getNameSpace());
            header.setBizobjectID(metadata.getHeader().getBizobjectID());
            header.setType(MetadataCustomizationUtils.RESOURCE_METADATA_TYPE);
            resourceMetadata.setHeader(header);
        }
        I18nResourceRTService i18nResourceRTService = I18nResourceRTUtils.getI18nResourceRTService();
        if (i18nResourceRTService == null) {
            return null;
        }

        i18nResourceRTService.mergeResourceMetadata(resourceMetadata, resouceItem);
        return MetadataDtoConverter.asDto(resourceMetadata);
    }

    @Override
    public List<DimensionExtendRelation> getDimExtRelationListByExtMetadataType(String metadataType) {
        if(StringUtils.hasText(metadataType)){
            List<GspMdExtRelation> extRelationList = extRelationRepoService.getExtRelationByExtMdType(metadataType);
            if(!CollectionUtils.isEmpty(extRelationList)){
                return extRelationList.stream().map(this::buildDimExtRelationByGspMdExtRelation).collect(Collectors.toList());
            }
        }
        return new ArrayList<>();
    }

    private I18nResource getResouceItem(GspMetadata metadata) {
        String type = metadata.getHeader().getType();
        MetadataI18nService i18nManager = I18nManagerHelper.getInstance().getI18nManager(type);
        if(i18nManager != null){
            return i18nManager.getResourceItem(metadata);
        }
        return null;
    }
    private String getResourceMetadataFileName(GspMetadata metadata) {
        String metadataSuffix = getMetadataSuffix(metadata.getHeader().getType());
        String resourceMetadataSuffix = getMetadataSuffix(MetadataCustomizationUtils.RESOURCE_METADATA_TYPE);
        return metadata.getHeader().getCode() + metadataSuffix + resourceMetadataSuffix;
    }
    private String getMetadataSuffix(String type) {
        MetadataType metadataType = MetadataTypeHelper.getInstance().getMetadataTypes().stream().filter(mt -> type.equals(mt.getTypeCode())).findFirst().orElse(null);
        ServiceUtils.checkNPE(metadataType, "此类型元数据：" + type + "，在配置文件中不存在。");
        return metadataType.getPostfix();
    }
}
